package cn.meike.net
{
	import cn.meike.net.protocol.KylinMsg;
	
	import flash.events.Event;
	import flash.events.IOErrorEvent;
	import flash.events.ProgressEvent;
	import flash.events.SecurityErrorEvent;
	import flash.net.Socket;
	import flash.system.Security;
	import flash.utils.ByteArray;
	import flash.utils.getTimer;

	public class BinarySocket
	{
		private var m_socket:Socket;
		private var m_dispatcher:NetEventDispatcher;
		
		public static const MSGTYPESTR:String = 'MsgType_';
		
		// TODO: 这两个不用每次都new，开始new一次然后往里面写就行了
		protected var m_sendBuf : ByteArray = null;
		protected var m_receiveBuf : ByteArray = null;
		protected var m_msgBuf:ByteArray = null;
		
		protected var m_msglen:int;
		
		public var time:uint;
		
		public function BinarySocket(d:NetEventDispatcher)
		{
			m_sendBuf = new ByteArray();
			m_receiveBuf = new ByteArray();
			m_msgBuf = new ByteArray();
			
			m_socket = new Socket();
			m_dispatcher = d;
		}
		
		public function connectByHost(strHost : String, nPort : int, nPolicyFilePort : int) : void
		{
			m_socket.addEventListener(Event.CONNECT, onConnected);
			m_socket.addEventListener(Event.CLOSE, onClosed);
			m_socket.addEventListener(ProgressEvent.SOCKET_DATA, onSocketData);
			m_socket.addEventListener(IOErrorEvent.IO_ERROR, onIOError);
			m_socket.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onSecurityError);
			
			if (nPolicyFilePort > 0/* && nPolicyFilePort != 843*/)
			{ 
				Security.loadPolicyFile("xmlsocket://" + strHost + ":" + nPolicyFilePort.toString()); 
			}
			
			m_socket.connect(strHost, nPort);
		}
		
		public function connectByIP(unIP : uint, nPort : int, nPolicyFilePort : int) : void
		{
			var temp : uint = unIP % 256;
			var host : String = temp.toString();
			
			for (var i : int = 0; i < 3; i++)
			{
				unIP = unIP >>> 8;
				temp = unIP % 256;
				host += "." + temp;
			}
			
			connectByHost(host, nPort, nPolicyFilePort);
		}
		
		public function get connected():Boolean
		{
			return m_socket.connected;
		}
		
		public function close():void
		{
			m_socket.removeEventListener(Event.CONNECT, onConnected);
			m_socket.removeEventListener(Event.CLOSE, onClosed);
			m_socket.removeEventListener(ProgressEvent.SOCKET_DATA, onSocketData);
			m_socket.removeEventListener(IOErrorEvent.IO_ERROR, onIOError);
			m_socket.removeEventListener(SecurityErrorEvent.SECURITY_ERROR, onSecurityError);
			
			try
			{
				m_socket.close();
			}
			catch (err : * ){}
		}
		
		protected function onConnected(event:Event):void
		{
			trace('socket-------------- onConnected');
			//			var traceMsg:String = "Time:"+TimeConvert.getDateTime()+ "socket Connected";
			//			qgame.utils.Log.trace("onConnected",Log.TFLOG);
			m_dispatcher.dispatchEvent(new NetEvent(NetEventTypes.SOCKET_CONNECT));
		}
		
		protected function onClosed(event:Event):void
		{
			trace('socket was closed by peer');
			//			var traceMsg:String = "  socket was closed by peer";
			//qgame.utils.Log.trace("连接关闭",Log.TFLOG);
			
			//manager.dispatcher.dispatchEvent(new ArgsEvent(EventTypes.SOCKET_CLOSE));
		}
		
		protected function onIOError(event:Event):void
		{
			trace('socket-------------- onIOError');
			//			var traceMsg:String ="socket onIOError";
			//Log.trace("IO异常！",Log.TFLOG);
			
			//manager.dispatcher.dispatchEvent(new ArgsEvent(EventTypes.SOCKET_IOERROR));
			
			//_popErrorDialog();
		}
		
		protected function onSecurityError(event:Event):void
		{
			trace('socket-------------- onSecurityError');
			var traceMsg:String = "socket onSecurityError";
			//Log.trace(traceMsg,Log.TFLOG);
			
			//manager.dispatcher.dispatchEvent(new ArgsEvent(EventTypes.SOCKET_SECURITYERROR));
			
			//_popErrorDialog();
		}
		
		/**
		 *socket发送 
		 * @param msg
		 * 
		 */
		public function sendPackage(msg:KylinMsg):void
		{
			//trace('socket------------- sendPackage');
			if(!connected)
			{
				return;
			}
			
			//记录时间
			time = getTimer();
			
			m_sendBuf.length = 0;
			m_sendBuf.position = 2;
			
			var i: int = msg.encode(m_sendBuf, KylinMsg.CURRVERSION);
			m_sendBuf.position = 0;
			
			m_sendBuf.writeShort(m_sendBuf.length);
			
			trace('m_sendBuf.length===',m_sendBuf.length,msg.m_stMsgHead.m_uiMsgID);
			
			m_socket.writeBytes(m_sendBuf);
			m_socket.flush();
		}
		 
		/**
		 *socket数据返回处理 
		 * @param event
		 * 
		 */
		protected function onSocketData(event:ProgressEvent):void
		{
			if (m_socket.bytesAvailable <= 0) 
			{
				return;
			}
			
			//记录时间
			time = getTimer();
			
			trace('收到数据：'+m_socket.bytesAvailable+":"+m_receiveBuf.length+'/'+m_receiveBuf.position);
			m_socket.readBytes(m_receiveBuf,m_receiveBuf.length);
			trace('缓冲区：'+m_receiveBuf.length+'/'+m_receiveBuf.position);
			
			m_receiveBuf.position = 0;
			
			//循环读包
			while(true)
			{
				if(m_receiveBuf.bytesAvailable<=2)
				{
					break;
				}
				
				m_msglen = m_receiveBuf.readUnsignedShort() - 2;
				
				//如果消息长度为0，说明是特殊的消息结构，否则为tdr消息
				if(0 - 2 != m_msglen)
				{
					if (m_receiveBuf.bytesAvailable >= m_msglen && m_msglen > 0)
					{
						m_msgBuf.length = 0;
						m_receiveBuf.readBytes(m_msgBuf,0,m_msglen);
						
						var msg:KylinMsg = new KylinMsg();
						
						msg.decode(m_msgBuf, KylinMsg.CURRVERSION);  
						
						//向游戏中发送网络消息
						dispatchEvent(msg.m_stMsgHead.m_uiMsgID,msg);
					}
					else
					{ 
						//如果不够一个包，就把长度回退
						m_receiveBuf.position -= 2; 
						break;
					}
				}
				else
				{
					trace("特殊消息解析  ...");				//特殊消息解析 by gavinsun 2011.7.19					
					// 读取消息单位长度
					//					var bodyLen :int = m_receiveBuf.readUnsignedShort();
					//m_receiveBuf.readUnsignedShort();
					
					// 消息Id
					//					var msgId :int = m_receiveBuf.readUnsignedShort();
					//m_receiveBuf.readUnsignedShort();
					
					// 结果Id
					//					var resultId :int = m_receiveBuf.readUnsignedShort();
					//m_receiveBuf.readUnsignedShort();
					
					//var errStr:String = m_receiveBuf.readUTF();
					
					//var msgBox :MessageBox = new MessageBox();
					//msgBox.setDefaultStyle();
					//msgBox.initMessage(true,
					//	'登录提示',
					//	errStr,
					//	1,
					//	'确定',
					//	0,
					//	this,
					//	_onReLogin,
					//	null,
					//	10);
					//msgBox.show();
				}
			}
			
			
			var len:int = m_receiveBuf.bytesAvailable;
			if(len>0)
			{
				//把后面的内容前移
				/*var p:uint = m_receiveBuf.position;
				m_receiveBuf.position = 0;
				m_receiveBuf.readBytes(m_receiveBuf, p, len);*/
				
				//Log.trace('有后续协议:'+m_msglen+'/'+len,Log.TFLOG);
				
				var p:uint = m_receiveBuf.position;
				var ba:ByteArray = new ByteArray();
				ba.position = 0;
				
				ba.writeBytes(m_receiveBuf,p,len);
				m_receiveBuf = ba;
				
				/*len = m_receiveBuf.bytesAvailable;
				var pos:int = m_receiveBuf.position;
				for (var i:uint = pos; i < pos+len; ++i)
				{
				m_receiveBuf[i-pos] = m_receiveBuf[i];	
				}
				m_receiveBuf.position = len;*/
				
				//m_receiveBuf.readBytes(m_receiveBuf, m_receiveBuf.position, len);
			}
			m_receiveBuf.length = len;
		}
		
		
		
		protected function dispatchEvent(msgID:uint,msg:KylinMsg):void
		{
			m_dispatcher.dispatchEvent(new NetEvent(MSGTYPESTR+msgID,msg));
		}
	}
	
	
}



